import queue
from binascii import b2a_hex
from datetime import datetime
from enum import Enum
from threading import Thread

from PySide2.QtCore import QThread, Signal
from PySide2.QtWidgets import QMessageBox
from src.app.app_debug import AppDebug
from src.app.app_dfu import AppDfu
from src.app.app_user import AppUser
from src.app.app_factory_burn import FactoryBurn
# from src.app.app_loop import AppLoop
from src.lib.errorno import g_errno_d
from src.lib.thread_stop import stop_thread
from src.module.serial_opt import AsyncioPort


class AppPort(QThread):

    rx_buff = queue.Queue()

    Page = Enum('Page', ('USER', 'DEBUG', 'CHART'))

    m_l_buff = []
    m_s_current_time = ""

    delivery_signal = Signal(int, str)
    upBar_signal = Signal(int)
    msg_signal = Signal(int, str, str)
    lampCfg_signal = Signal(list)

    def __init__(self, ui):
        super(AppPort, self).__init__()

        self.ui = ui
        self.MainWindow = self.ui.MainWindow
        self.MyPort = AsyncioPort(self.rx_callback, self.err_callback)

        self.Debug = AppDebug(ui, self)
        self.Dfu = AppDfu(ui, self)
        self.User = AppUser(ui, self)
        self.FactoryBurn = FactoryBurn(ui, self)

    def rx_callback(self, data):
        self.rx_buff.put(data)

    def err_callback(self, msg):
        print("err", msg)
        if msg.find('close') != -1:
            # 解决串口异常关闭，导致UI界面仍显示串口打开状态
            if self.MainWindow.btn_switchSerial.text() == "关闭":
                self.uiPortClose()

    def task_receive(self):
        while 1:
            try:
                # 传入字节集(非字符串)
                self.__portReceive(self.rx_buff.get())
            except Exception:
                pass

    # 得到串口状态(0--打开  1--关闭)
    def getPortState(self):
        return self.MyPort.is_closing()

    def uiPortCheck(self):
        port_list = []
        port_list = self.MyPort.getPortList()
        self.MainWindow.cmb_serialNum.clear()
        for port in port_list:
            self.MainWindow.cmb_serialNum.addItem(port)

    def __controlSwitch(self, state):
        self.MainWindow.cmb_serialNum.setEnabled(state)
        self.MainWindow.btn_scanSerial.setEnabled(state)

    def uiPoerOpen(self):
        ret = self.openPort()
        if ret != g_errno_d['OK']:
            QMessageBox.critical(self.ui, "Port Error", "此串口不能被打开！")
        else:
            self.MainWindow.btn_switchSerial.setText("关闭")
            self.__controlSwitch(False)
            '''线程启动'''
            self.rx = ""
            self.rx = Thread(target=self.task_receive, daemon=True)
            self.rx.start()

    def uiPortClose(self):
        self.closePort()
        self.MainWindow.btn_switchSerial.setText("连接")
        self.__controlSwitch(True)
        '''线程终止Kill'''
        stop_thread(self.rx)

    def uiPortSwitch(self):
        if self.MainWindow.btn_switchSerial.text() == "连接":
            self.uiPoerOpen()
        else:
            self.uiPortClose()

    def openPort(self):
        ret = self.MyPort.open(self.MainWindow.cmb_serialNum.currentText(), 115200)
        return ret

    def sendMsg(self, data):
        self.m_s_current_time = self.getCurrentTime()
        self.MyPort.sendMsg(data)

    def closePort(self):
        self.MyPort.close()
        self.rx_buff.queue.clear()

    def getCurrentTime(self):
        try:
            return datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
        except Exception:
            return "0-0-0-0"

    def getTimeStrAndText(self, text):
        try:
            return ('[' + self.m_s_current_time + "] " + text + '\r\n')
        except Exception:
            return (self.m_s_current_time + "\n" + "(Hex) " +
                    str(b2a_hex(text))[2:-1] + '\r\n')

    # 将文本追加至末尾
    def sendTextToReceive(self, page, text):
        self.delivery_signal.emit(page, text)

    def __portReceive(self, text):
        print("rx:", text)
        try:
            text = text.decode()
        except Exception:  # 如果解码失败则直接把字节集转发给指定页
            print("解密失败", text.hex())
            return

        # -------------------以下处理粘包------------------------
        at_s = ""
        up_s = ""
        pm_s = ""
        try:
            buff = text.split("\r\n")
            if len(buff) != 0:
                for data in buff:
                    if data.find("UP^") != -1:
                        up_s += data + "\r\n"
                    elif data.find("PM^") != -1:
                        pm_s += data + "\r\n"
                    else:
                        at_s += data + "\r\n"
        except Exception:
            pass

        # 判断是否存在AT命令
        if len(at_s) > 0:
            at_s = at_s[:-2]
            # Page --> Debug
            self.Debug.uiForwardReceive(at_s)

        if len(up_s) > 0:
            if self.Dfu.m_i_upgrade_flag == 1:
                self.Dfu.BootUp.rx_buff.put(up_s)
            if up_s.find("UP^OK,dfu mode") > -1:
                self.Debug.uiForwardReceive("进入DFU状态-->\r\n")

